using System;
using System.Collections.Generic;
using System.Text;
using NHibernate;
using NHibernate.Cfg;
using Ksibo.Modelo;
using NHibernate.Expression;

namespace Ksibo.Dados
{
    public class ConexaoBD<T>
    {
        public static ISession conexao;
        private static ITransaction transacao;

        public ConexaoBD()
        {
        }
        #region trecho comentado
        /*public IList<PosicaoFila> GetFilaByPrioridade(int idRevista, int prioridade)
        {
            PreparaConexao();
            transacao = conexao.BeginTransaction();
            try
            {
                ICriteria crit = conexao.CreateCriteria(typeof(PosicaoFila));
                crit.Add(Expression.Eq("IdRevista", idRevista));
                crit.Add(Expression.Eq("PrioridadeFila", prioridade));
                IList<PosicaoFila> posicoesDaFila = crit.List<PosicaoFila>();
                transacao.Commit();
                conexao.Disconnect();
                return posicoesDaFila;
            }
            catch (Exception ex)
            {
                transacao.Rollback();
                return null;
            }                       
        }
        public Usuario GetUsuarioByLogin(string login)
        {
            PreparaConexao();
            transacao = conexao.BeginTransaction();
            try
            {
                ICriteria crit = conexao.CreateCriteria(typeof(Usuario));
                crit.Add(Expression.Eq("Login", login));
                Usuario retorno = (Usuario)crit.UniqueResult();
                transacao.Commit();
                conexao.Disconnect();
                return retorno;
            }
            catch (Exception ex)
            {
                transacao.Rollback();
                return null;
            }
        }
        public Usuario GetUsuarioById(int id)
        {
            PreparaConexao();
            transacao = conexao.BeginTransaction();
            try
            {
                ICriteria crit = conexao.CreateCriteria(typeof(Usuario));
                crit.Add(Expression.Eq("Id", id));
                Usuario retorno = (Usuario)crit.UniqueResult();
                transacao.Commit();
                conexao.Disconnect();
                return retorno;
            }
            catch (Exception ex)
            {
                transacao.Rollback();
                return null;
            }
        }    
        */
        #endregion
        public static bool Atualiza(T obj)
        {
            try
            {
                Conecta();
                conexao.Update(obj);
                Desconecta(Definicoes.TRANSACAO_SEM_ERRO);
                return true;
            }
            catch (Exception exp)
            {
                Console.WriteLine(exp.ToString());
                Desconecta(Definicoes.TRANSACAO_COM_ERRO);
                return false;
            }
        }

        public static IList<T> Busca(params AbstractCriterion[] xp)
        {
            try
            {
                Conecta();
                ICriteria crit = conexao.CreateCriteria(typeof(T));
                foreach (AbstractCriterion esp in xp)
                {
                    crit.Add(esp);
                }
                IList<T> retorno = crit.List<T>();

                Desconecta(Definicoes.TRANSACAO_SEM_ERRO);
                return retorno;
            }
            catch (Exception exp)
            {
                Console.WriteLine(exp.ToString());
                Desconecta(Definicoes.TRANSACAO_COM_ERRO);
                return null;
            }
        }

        public static IList<T> Busca(Order order, params AbstractCriterion[] xp)
        {
            try
            {
                Conecta();
                ICriteria crit = conexao.CreateCriteria(typeof(T));
                foreach (SimpleExpression esp in xp)
                {
                    crit.Add(esp);
                }
                crit.AddOrder(order);
                IList<T> retorno = crit.List<T>();

                Desconecta(Definicoes.TRANSACAO_SEM_ERRO);
                return retorno;
            }
            catch (Exception exp)
            {
                Console.WriteLine(exp.ToString());
                Desconecta(Definicoes.TRANSACAO_COM_ERRO);
                return null;
            }
        }

        public static IList<T> BuscaTodos(params int[] ids)
        {
            try
            {
                Conecta();
                IList<T> retorno = new List<T>();
                foreach (int id in ids)
                {
                    T obj = conexao.Load<T>(id);
                    if (obj != null)
                    {
                        retorno.Add(obj);
                    }
                }
                Desconecta(Definicoes.TRANSACAO_SEM_ERRO);
                return retorno;
            }
            catch (Exception exp)
            {
                Console.WriteLine(exp.ToString());
                Desconecta(Definicoes.TRANSACAO_COM_ERRO);
                return null;
            }
        }


        public static T BuscaUnico(params SimpleExpression[] xp)
        {
            try
            {
                Conecta();
                ICriteria crit = conexao.CreateCriteria(typeof(T));
                foreach (SimpleExpression esp in xp)
                {
                    crit.Add(esp);
                }
                T retorno = crit.UniqueResult<T>();
                Desconecta(Definicoes.TRANSACAO_SEM_ERRO);
                return retorno;
            }
            catch (Exception exp)
            {
                Console.WriteLine(exp.ToString());
                Desconecta(Definicoes.TRANSACAO_COM_ERRO);
                return default(T);
            }
        }
        public static T BuscaById(int id)
        {
            try
            {
                Conecta();
                T retorno = conexao.Load<T>(id);
                Desconecta(Definicoes.TRANSACAO_SEM_ERRO);
                return retorno;
            }
            catch (Exception exp)
            {
                Console.WriteLine(exp.ToString());
                Desconecta(Definicoes.TRANSACAO_COM_ERRO);
                return default(T);
            }
        }
        public static bool Salva(T obj)
        {
            try
            {
                Conecta();
                conexao.Save(obj);
                Desconecta(Definicoes.TRANSACAO_SEM_ERRO);
                return true;
            }
            catch (Exception exp)
            {
                Console.WriteLine(exp.ToString());
                Desconecta(Definicoes.TRANSACAO_COM_ERRO);
                return false;
            }

        }
        public static bool Deleta(params int[] id)
        {
            try
            {                
                foreach (int cada_id in id)
                {
                    T objeto = conexao.Load<T>(cada_id);
                    Conecta();
                    conexao.Delete(objeto);
                }
                conexao.Flush();
                Desconecta(Definicoes.TRANSACAO_SEM_ERRO);
                return true;
            }
            catch (Exception exp)
            {
                Console.WriteLine(exp.ToString());
                Desconecta(Definicoes.TRANSACAO_COM_ERRO);
                return false;
            }
        }
        public static bool Deleta(IList<T> objeto)
        {
            try
            {
                Conecta();
                foreach (T obj in objeto)
                {
                    conexao.Delete(obj);
                }
                conexao.Flush();
                Desconecta(Definicoes.TRANSACAO_SEM_ERRO);
                return true;
            }
            catch (Exception exp)
            {
                Console.WriteLine(exp.ToString());
                Desconecta(Definicoes.TRANSACAO_COM_ERRO);
                return false;
            }
        }
        public static bool Deleta(T objeto)
        {
            try
            {
                Conecta();
                conexao.Delete(objeto);
                conexao.Flush();
                Desconecta(Definicoes.TRANSACAO_SEM_ERRO);
                return true;
            }
            catch (Exception exp)
            {
                Console.WriteLine(exp.ToString());
                Desconecta(Definicoes.TRANSACAO_COM_ERRO);
                return false;
            }
        }


        public static bool Deleta(params SimpleExpression[] exp)
        {
            try
            {                
                T objeto = BuscaUnico(exp);
                Conecta();
                conexao.Delete(objeto);
                conexao.Flush();
                Desconecta(Definicoes.TRANSACAO_SEM_ERRO);
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                Desconecta(Definicoes.TRANSACAO_COM_ERRO);
                return false;
            }
        }
        private static void Conecta()
        {
            try
            {
                if (conexao == null || !conexao.IsOpen)
                {
                    Configuration cfg = new Configuration();
                    cfg.AddAssembly("Ksibo");
                    ISessionFactory factory = cfg.BuildSessionFactory();
                    conexao = factory.OpenSession();                    
                }
                else if (!conexao.IsConnected)
                {
                    conexao.Reconnect();
                }
                transacao = conexao.BeginTransaction();
            }
            catch (Exception ex)
            {

                throw ex;
            }
        }
        private static void Desconecta(bool ocorreuErro)
        {
            try
            {
                if (ocorreuErro)
                {
                    transacao.Rollback();
                    conexao.Disconnect();
                }
                else
                {
                    transacao.Commit();
                    conexao.Disconnect();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}
